<?php

	abstract class AbstractField extends EavAppModel
	{
		
		var $fieldProperties = array(
			'id'=>array('group'=>array('grid')),
			'name'=>array('fieldModifier'=>"valueTolowerCase"),
			'label'=>array('type'=>"text",'group'=>array('add','grid','edit'),'validate'=>array('rule'=>VALID_NOT_EMPTY,'required'=>true)),
			'type'=>array('type'=>"select",'group'=>array('add','grid','edit'),'empty'=>"-Select-",'validate'=>array('rule'=>VALID_NOT_EMPTY,'required'=>true),),
			'required'=>array('type'=>"select",'options'=>array('No','Yes'),'empty'=>'-Select-','group'=>array('add','edit')),
			'value'=>array('type'=>"text",'label'=>"Default value",'group'=>array('add','edit')),
			'tooltip'=>array('type'=>"text",'group'=>array('add','edit')),
			'options'=>array('group'=>array('add','edit'), 'fieldModifier'=>'toggleSerialized'),		
			'group'=>array('group'=>array('add','grid','edit'),'type'=>'select','multiple'=>true,'fieldModifier'=>'toggleSerialized')
		);
		/**
		 * Class of fieldset model. 
		 * @var unknown_type
		 */
		protected $fieldsetModelName;
		protected $fieldsetModelAlias;
		/**
		 * A list of models for which fields will be merged with schema.
		 * @var array
		 */
		protected $schemModels = array();
		
		/**
		 * Class of fieldOption model.
		 * @var unknown_type
		 */
		protected $fieldOptionModelName = null;
		protected $fieldOptionModelAlias = null;
		
		function initialize()
		{
			$this->setFieldProperties('type',array('options'=>$this->getFieldTypes()));
			$this->setFieldProperties('group',array('options'=>$this->getGroupTypes()));
			$group = array('add','grid');
			$requiredRule = array('rule' => VALID_NOT_EMPTY,'message'=>__('This field is required'),'required'=>true);
			if($this->allowNameEdit())
			{
				$group[] = 'edit';
			}else
			{
				$requiredRule['on'] = 'create';
			}
			$validate = array($requiredRule,
						array('rule'=>'unique','message'=>__("This name is already in use.")),
						array('rule'=>array('custom','/^\w+$/'),'message'=>__("Please enter alphanumeric and underscore  characters only.")),
						array("rule"=>"validateIsModelSchemaField","message"=>__("This name is already in use.")));
			$this->setFieldProperties('name',array('type'=>"text",'group'=>$group,'validate'=>$validate));
			if($this->useSeparateFieldOption())
			{
				$this->setFieldProperties("options", array(
						"group"=>array("add","edit"),
						'type'=>"parent",
						'childInfo' => array(
								'model'=>$this->fieldOptionModelName,
								'allowEdit' => true,
								'child_group' => "add",
								'allowMultiple' => true,
								'deleteMissing' => true,
						),
						'fieldModifier'=>'toggleSerialized',
						'fieldset' => false,
				));
			} else {
				$this->setFieldProperties('options',array('type'=>"textarea",'fieldModifier'=>'toggleSerialized','group'=>array('add','edit')));
			}
			parent::initialize();
		}
	
		function afterInitialize()
		{
			if($this->useFieldset())
			{
				$this->fieldsetModelConfig();
			}
			parent::afterInitialize();			
		}
		/**
		 * Return available field types
		 */
		function getFieldTypes()
		{
			return array (
				'text' => __('Text'),
				'textarea' => __('Multiple Line Text'),
				'select' => __('Option box'),
				'radio' => __('Radio Buttons'),
				'number' => __('Number'),
				'checkbox' => __('Checkbox'),
				'editor' => __('HTML Editor'),
				'currency'=>__("Currency"),
				'datetime' => __('Date & Time'),
				'date' => __('Date'),
				//'year'=>__("Year"),
				//'time' => __('Time'),
				'multipleSelect' => __('Multiple Choice Option box'),
				'multipleCheckbox' => __('Checkboxes Group'),
				'email'=> __('Email'),
				
				//'colorPicker' => __('Color Picker'),
				//'slider' => __('Slider'),
				//'datePicker' => __('Datepicker Widget'),
				//'countrySuggestor' => __('Country List'),
				//'parent' => __('Parent Field')
			);
		}
		/**
		 * abstract method to flag use of fielsetmodel
		 */
		abstract function useFieldset();
		/**
		 * return fieldset model instance
		 */
		function getFieldsetModel()
		{
			if(!$this->fieldsetModelName)
			{
				throw new Exception("No fieldset model name specified for $this->alias model");
			}
			return $this->{$this->getFieldsetModelAlias()};
		}
		/**
		 * return fieldset model alias
		 */
		function getFieldsetModelAlias()
		{
			if(!$this->fieldsetModelAlias)
			{
				$this->fieldsetModelAlias = array_pop(explode('.',$this->fieldsetModelName));
			}
			return $this->fieldsetModelAlias;
		}
		/**
		 * Set assocation and fieldpropeties related to Fieldset Model.
		 * @param unknown_type $config
		 */
		protected function fieldsetModelConfig($config = array())
		{
			$config['className'] = $this->fieldsetModelName; 
			$this->bindModel(array('belongsTo'=>array($this->getFieldsetModelAlias() => $config)),false);
			$this->setFieldProperties($this->getFieldsetModel()->foreignKey,array('group'=>array('add','grid'),'label'=>__("Fieldset"),'empty'=>__("-Select-")));
			$this->addValidationRule($this->getFieldsetModel()->foreignKey,array('rule'=>VALID_NOT_EMPTY,'required'=>true,));
		}
		/**
		 * Return list of created fieldsets.
		 */
		function getFieldsets()
		{
			$fieldsets = $this->getFieldsetModel()->find('list',array('conditions'=>array(),'fields'=>array('id','name')));
			return $fieldsets;
		}
		/**
		 * Return list groups available for field.
		 */
		function getGroupTypes()
		{
			return array();
		}
		/**
		 * Tell wether name can be allowed to edited or not.
		 */
		function allowNameEdit()
		{
			return false;
		}
		
		function beforeSave($options)
		{
			//do not name edit accordign to configuration
			if(isset($this->data[$this->alias]['name']) && $this->_isNew() == false && $this->allowNameEdit() == false)
			{
				unset($this->data[$this->alias]['name']);
			}
			return parent::beforeSave($options);
		}
		/**
		 * return field types which requires options.
		 */
		function getOptionsFieldType()
		{
			return array('select','radio','checkbox','multipleSelect','multipleCheckbox');
		}
		
		function valueTolowerCase($value,$action)
		{
			if(self::SAVE == $action)
			{
				$value = low($value);
			}
			return $value;
		}
		/**
		 * Validates whether field name is already prersnt
		 * in schema models or not. 
		 * @param $data
		 */
		function validateIsModelSchemaField($data)
		{
			$fieldName =	array_shift($data);
			$exists = false;
			foreach($this->schemModels as $schemaModel)
			{
				$modelInst = cri($schemaModel);
				if($modelInst->hasField($fieldName))
				{
					$exists = true 	;
				}
			}
			return !$exists;
			
		}
		
		

		/**
		 * method to flag use of fieldOptionModel, <br>if set flag to true then also set the followings <br> protected var fieldOptionModelName to field option child model class name <br/> method getFieldOptionParentFieldName() can be override if the field model id field_name is different in child model <br/> method getFieldOptionValueFieldName() can be override if the field_name is different from "field_value"<br/>
		 */
		function useSeparateFieldOption()
		{
			return false;
		}
		/**
		 * return fieldOption model instance
		 */
		function getFieldOptionModel()
		{
			if(!$this->fieldOptionModelName)
			{
				throw new Exception("No fieldOption model name specified for $this->alias model");
			}
			return $this->{$this->getFieldOptionModelAlias()};
		}
		/**
		 * return fieldOption model alias
		 */
		function getFieldOptionModelAlias()
		{
			if(!$this->fieldOptionModelAlias)
			{
				$this->fieldOptionModelAlias = array_pop(explode('.',$this->fieldOptionModelName));
			}
			return $this->fieldOptionModelAlias;
		}
		
		/**
		 * return foreign key field name for fieldOption model's parent model 
		 */
		function getFieldOptionParentFieldName()
		{
			if(!$this->fieldOptionModelName)
			{
				throw new Exception("No fieldOption model name specified for $this->alias model");
			}
			$fieldName = Inflector::underscore($this->alias)."_id";
			return $fieldName;
		}
		
		/**
		 * return field name for fieldOption model which contain options data
		 * @throws Exception
		 * @return string
		 */
		function getFieldOptionValueFieldName()
		{
			if(!$this->fieldOptionModelName)
			{
				throw new Exception("No fieldOption model name specified for $this->alias model");
			}
			return "field_value";
		}
		
		function _processFieldOptionsAfterSave($fieldId)
		{
			$fieldOptionsList = $this->getFieldOptionModel()->find('list',array('conditions'=>array($this->getFieldOptionModelAlias().".".$this->getFieldOptionParentFieldName() => $fieldId),'fields'=>array('key',$this->getFieldOptionValueFieldName()),'order'=>array('sort_order'=>'ASC'),'recursive'=>-1));
			$fieldOptionsList = serialize($fieldOptionsList);
			$this->saveField('options', $fieldOptionsList, false, false);
		}
		
	}
?>